package com.matrix.gui;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import com.matrix.math.*;
import com.matrix.utils.*;

/**
 * This is the main activity of Matrix Pack. every thing in the main activity is handled here.
 * 
 * The UI custom widgets are Box.java and ListItem.java 
 * 
 * This class uses the following XML files:
 * 	
 * 	1- dialog.xml
 *  2- listitem.xml
 *  3- main_activity.xml
 *  4- box1_menu.xml
 *  5- box2_menu.xml
 *  6- list_menu.xml
 *  7- main_menu.xml
 *  8- arrays.xml
 *  9- colors.xml
 *  10-dimens.xml
 *  11-strings.xml
 * 
 * @author Sultan
 * Last modified: April 27th, 2011
 * 
 */
public class MainActivity extends Activity
{
	/**
	 * Instance Variables
	 */
	private Parser parser;
	private Alert dialog;
	private Spinner spinner;
	private EditText editText;
	private Box left, right;
	private Button switchButton, calculate, reset;
	private ListView listView;
	private ArrayAdapter<?> spinnerAdapter, listAdapter;
	private Globals global;
	private int operation; // integer to hold the operation in the spinner
	private Matrix matrix; // to be added to the list 
	private Vector vector;
	private Constant constant;
	private ColumnVector colVect;
	private Intent intent;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
        this.init();
    }

	
    /**
     * Method to initialize all objects to be used in the application
     */
    public void init()
    {
        this.global = (Globals) this.getApplicationContext();
        this.parser = new Parser();
        this.dialog = new Alert(this);
    	this.findViews();
    	this.setAdapters();
    	this.addListeners();
    	this.registerForContextMenu(listView);
    	this.registerForContextMenu(left);
    	this.registerForContextMenu(right);
    }
    
    /**
     * Method to link objects created in this activity to their correspondence in the XML file.
     * @return void
     */
    public void findViews()
    {
    	this.spinner = (Spinner) this.findViewById(R.id.mat_act_spinner);
    	this.editText = (EditText) this.findViewById(R.id.mat_act_edittext);
    	this.left = (Box) this.findViewById(R.id.mat_act_box1);
    	if(global.getLeft() >-1)
    	{
    		left.setText(global.get(global.getLeft()).getName());
    	}
    	this.right = (Box) this.findViewById(R.id.mat_act_box2);
    	if(global.getRight() >-1)
    	{
    		right.setText(global.get(global.getRight()).getName());
    	}
    	this.switchButton = (Button) this.findViewById(R.id.mat_act_switch);
    	this.calculate = (Button) this.findViewById(R.id.mat_act_calculate);
    	this.reset = (Button) this.findViewById(R.id.mat_act_reset);
    	this.listView = (ListView) this.findViewById(R.id.mat_act_listview);
    }
    
    /**
     * Method to set the adapters of the spinner, and the listView objects.
     */
    public void setAdapters()
    {
    	int resID = R.layout.listitem;
    	this.spinnerAdapter = ArrayAdapter.createFromResource(this,
				R.array.matrix_ops, android.R.layout.simple_spinner_item);
    	this.spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    	this.spinner.setAdapter(spinnerAdapter);
    	this.listAdapter = new ArrayAdapter<MathObject>(this, resID, global.getListItems());
    	this.listView.setAdapter(listAdapter);
    }
    /**
     * Method to add listeners to interactive widgets used in the main activity.
     */
    public void addListeners()
    {
    	this.spinner.setOnItemSelectedListener(new OnItemSelectedListener()
    	{
			public void onItemSelected(AdapterView<?> parent, View view,
					int position, long id)
			{
				setOperation(position);
			}

			public void onNothingSelected(AdapterView<?> parent)
			{/* Do nothing */}
    	}); // end spinner
    	
    	this.editText.setOnKeyListener(new OnKeyListener()
    	{
			public boolean onKey(View v, int keyCode, KeyEvent event)
			{
				if ((event.getAction() == KeyEvent.ACTION_DOWN) && 
						(keyCode == KeyEvent.KEYCODE_ENTER)) 
				{
					// enter was pressed 
					add();
					InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);            
					imm.hideSoftInputFromWindow(v.getApplicationWindowToken(), 0);
					return true;
				}
				return false;
			}
    	});
    
    	this.left.setOnClickListener(new OnClickListener()
    	{
			public void onClick(View v)
			{
				//check if global left is -1 throw exception box is empty
				if(global.getLeft() < 0)
				{
					dialog.error("box is empty");
				}
				viewLeftBox();
			}
    	});
    	
    	this.right.setOnClickListener(new OnClickListener()
    	{
			public void onClick(View v)
			{
				//check if global right is -1 throw exception box is empty
				if(global.getRight() < 0)
				{
					dialog.error("box is empty");
				}
				viewRightBox();
			}
    	});
    	
    	this.calculate.setOnClickListener(new OnClickListener()
    	{
			public void onClick(View v)
			{
				calculate();
			}    		
    	});
    	this.reset.setOnClickListener(new OnClickListener()
    	{
			public void onClick(View v)
			{
				reset();
			}    		
    	});
    	this.switchButton.setOnClickListener(new OnClickListener()
    	{
			public void onClick(View v)
			{
				switchBoxes();
			}    		
    	});
		this.listView.setOnItemClickListener(new OnItemClickListener()
		{
			public void onItemClick(AdapterView<?> parent, View v,
					int position, long id)
			{
				// get which box is empty
				if(global.getLeft() < 0)
				{
					global.setLeft(position);
					left.setText(global.get(global.getLeft()).getName());
				}
				else if(global.getRight() < 0)
				{
					global.setRight(position);
					right.setText(global.get(global.getRight()).getName());
				}
				else
				{
					global.setLeft(position);
					left.setText(global.get(global.getLeft()).getName());
				}
			}	
		});
    }// end addListeners();

	/**
	 * Create a Menu for the matrix activity. This method receives a 
	 * Menu object as a parameter.
	 * 
	 * @param Menu object
	 * @return true if menu is created
	 */
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		MenuInflater inflater = this.getMenuInflater();
		inflater.inflate(R.menu.main_mene, menu);
		return true;
	}
	
	/**
	 * This method will execute when a menu item is selected 
	 * from the main menu.
	 * @param menu item
	 * @return true if the action is handled successfully
	 * 
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		super.onOptionsItemSelected(item);
		
		switch (item.getItemId()) {
			case (R.id.menu_main_add): 
			{
				this.add();
				return true;
			}
			case (R.id.Menu_main_calculate):
			{
				this.calculate();
				return true;
			}
			case(R.id.menu_main_reset):
			{
				global.getListItems().clear();
				this.listAdapter.notifyDataSetChanged();
				reset();
				return true;
			}
			case(R.id.menu_main_open):
			{
				intent = new Intent(this, LoadMatrix.class);
				startActivityForResult(intent, 0);
				return true;
			}
			case(R.id.menu_main_save):
			{
				FileIO f = new FileIO();
				try {
					f.saveSession("session", global.getListItems());
				} catch (Exception e) {
					// TODO Auto-generated catch block
					dialog.error(e.getMessage());
				}
				return true;
			}
			case(R.id.menu_main_help):
			{
				intent = new Intent(this, Help.class);
				startActivity(intent);
				return true;
			}
			
		}

		return false;
	}
	
	/**
	 * Method to notify the listView of some changes that might have been made in some other
	 * Activities, namely 'ResultActivity' after the call to the method 'startActivityForResult'.
	 */
	protected void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		this.listAdapter.notifyDataSetChanged();
	}
	
	/**
	 * This method creates the context menu for registered views used in this
	 * activity.
	 * @param context menu object, a view, and a menu info.
	 * @return void
	 */
	@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenu.ContextMenuInfo menuInfo) {
		super.onCreateContextMenu(menu, v, menuInfo);
		MenuInflater inflater = this.getMenuInflater();
		
		switch(v.getId())
		{
		case (R.id.mat_act_listview):
		{
			inflater.inflate(R.menu.list_menu, menu);
		}break;
		case (R.id.mat_act_box1):
		{
			inflater.inflate(R.menu.box1_menu, menu);
		}break;
		case (R.id.mat_act_box2):
		{
			inflater.inflate(R.menu.box2_menu, menu);
		}break;
		default: {}
		}		
	}
	
	/**
	 * This method handles the the actions performed by the user on.
	 * the context menu.
	 * @param menu item.
	 * @return true if handled successfully.
	 */
	@Override
	
	public boolean onContextItemSelected(MenuItem item) {
	
		super.onContextItemSelected(item);
        AdapterView.AdapterContextMenuInfo menuInfo;
        menuInfo =(AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
        int index = 0;
        try // try because the calling UI element might not be the list which has position integer
        {
        	index = menuInfo.position;
        }
        catch(Exception e)
        {}
        	
	    switch (item.getItemId())
	    {
	      case (R.id.menu_context_list_remove):
	      {
	    	  global.getListItems().remove(index);
	    	  if(index == global.getLeft())
	    	  {
	    		  removeLeftBox();
	    	  }
	    	  if(index == global.getRight())
	    	  {
	    		  removeRightBox();
	    	  }
	    	  this.listAdapter.notifyDataSetChanged();
	    	  return true;
	      }
	      case (R.id.menu_context_box1_view):
	      {
	    	  viewLeftBox();
	    	  return true;
	      }
	      case (R.id.menu_context_box1_remove):
	      {
	    	  removeLeftBox();
	    	  return true;
	      }
	      case (R.id.menu_context_box2_view):
	      {
	    	  viewRightBox();
	    	  return true;
	      }
	      case (R.id.menu_context_box2_remove):
	      {
	    	  removeRightBox();
	    	  return true;
	      }
	    }
	    return false;
	}
	
	
	/**
	 * Method to parse the string in the edit field and add it to the listView.
	 * @return void.
	 */
    public void add()
    {
    	int object;
    	this.parser.clear(); // clear parser object
    	this.parser.setToken(editText.getText().toString());
    	try
    	{
			object = this.parser.parse(); // object is an integer holding the object type ex. 1 for matrix 2 for vector @see {@linked Parser.java}
			switch(object)
	    	{
		    	case 1:
		    		{
		    			this.matrix = this.parser.getMatrix();
		   				if(this.matrix.getName().equals(""))
		    			{
		    				this.matrix.setName(matrix.getTag()+(global.getCount()));
		    				global.incCount();
		    				global.getListItems().add(matrix);
		   				}
		    			else
		    			{
		    				global.getListItems().add(matrix);
		    			}
		    		} break;
		    		
		    	case 2:
		    		{
		    			this.vector = this.parser.getVector();
		    			if(this.vector.getName().equals(""))
		    			{
		    				this.vector.setName(vector.getTag()+(global.getCount()));
		    				global.incCount();
		    				global.getListItems().add(vector);
		   				}
		   				else
		   				{
		   					global.getListItems().add(vector);
	    				}
		    		} break;
		    	case 3:
	    		{
	    			this.constant = this.parser.getConstant();
	    			if(this.constant.getName().equals(""))
	    			{
	    				this.constant.setName(constant.getTag()+(global.getCount()));
	    				global.incCount();
	    				global.getListItems().add(constant);
	   				}
	   				else
	   				{
	   					global.getListItems().add(constant);
    				}
	    		} break;
		    	case 4:
	    		{
	    			this.colVect = this.parser.getColVect();
	    			if(this.colVect.getName().equals(""))
	    			{
	    				this.colVect.setName(colVect.getTag()+(global.getCount()));
	    				global.incCount();
	    				global.getListItems().add(colVect);
	   				}
	   				else
	   				{
	   					global.getListItems().add(colVect);
    				}
	    		} break;
		    	default: {/* No way */}
	    	} // end switch
			editText.setText("");
		   	this.listAdapter.notifyDataSetChanged();
		}
    	catch (Exception e)
		{
    		// wrong entry
    		this.dialog.error(e.getMessage());
			e.printStackTrace();
		}

    }
    
    /**
     * This method calculates the result and then views it in another activity or in a dialog.
     * @return void.
     */
    public void calculate()
    {
    	switch(operation)
    	{
    	case 0: // matrix addition
    		if(!someOrBothBoxesFilled()) return;
    		try
    		{
    			this.matrix = (Matrix) global.get(global.getLeft());
				global.setResultMatrix(this.matrix.add((Matrix)global.get(global.getRight())));
				intent = new Intent(this, ResultView.class);
				global.setOpType(0);
				startActivityForResult(intent, 0);
			} catch (Exception e){
				dialog.error(e.getMessage());
				e.printStackTrace();
			}
    		break;
    	case 1: //Matrix:Multiplication
    		if(!someOrBothBoxesFilled()) return;
    		try
    		{
    			this.matrix = (Matrix) global.get(global.getLeft());
				global.setResultMatrix(this.matrix.multMatrix((Matrix)global.get(global.getRight())));
				intent = new Intent(this, ResultView.class);
				global.setOpType(0);
				startActivityForResult(intent, 0);
			} catch (Exception e) {
				dialog.error(e.getMessage());
				e.printStackTrace();
			}
    		break;
    	case 2: //Matrix:Transpose
    		
    		if(BothBoxesFilled())
    		{
    			dialog.ask(this.left.getText().toString(), this.right.getText().toString());
    		}
    		else if(!(global.getLeft() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());    				
					global.setResultMatrix(this.matrix.transpose());
					intent = new Intent(this, ResultView.class);
					global.setOpType(0);
					startActivityForResult(intent, 0);
				} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else if(!(global.getRight() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());    				
					global.setResultMatrix(this.matrix.transpose());
					intent = new Intent(this, ResultView.class);
					global.setOpType(0);
					startActivityForResult(intent, 0);
				} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			dialog.error("The two boxes are empty");
    		}
    		
    		break;
    	case 3: //Matrix:Inverse
    		
    		if(BothBoxesFilled())
    		{
    			dialog.ask(this.left.getText().toString(), this.right.getText().toString());
    		}
    		else if(!(global.getLeft() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());    				
					global.setResultMatrix(this.matrix.inverse());
					intent = new Intent(this, ResultView.class);
					global.setOpType(0);
					startActivityForResult(intent, 0);
				} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else if(!(global.getRight() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());    				
					global.setResultMatrix(this.matrix.inverse());
					intent = new Intent(this, ResultView.class);
					global.setOpType(0);
					startActivityForResult(intent, 0);
				} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			dialog.error("The two boxes are empty");
    		}
    		break;
    	case 4: //Matrix:Determinant
    		if(BothBoxesFilled())
    		{
    			dialog.ask(this.left.getText().toString(), this.right.getText().toString());
    		}
    		else if(!(global.getLeft() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());
	    			dialog.show("Result", this.matrix.determinant()+"");
				} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else if(!(global.getRight() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());
	    			dialog.show("Result", this.matrix.determinant()+"");
	    		} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			dialog.error("The two boxes are empty");
    		}
    		break;
    	case 5: //Matrix:P-L-U Factorization
    		if(BothBoxesFilled())
    		{
    			dialog.ask(this.left.getText().toString(), this.right.getText().toString());
    		}
    		else if(!(global.getLeft() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());
    				global.setResultMatrix(matrix.pluFactorization());
    				intent = new Intent(this, ResultView.class);
    				global.setOpType(5);
    				startActivityForResult(intent, 0);
				} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else if(!(global.getRight() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());
    				global.setResultMatrix(matrix.pluFactorization());
    				intent = new Intent(this, ResultView.class);
    				global.setOpType(5);
    				startActivityForResult(intent, 0);
    			} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			dialog.error("The two boxes are empty");
    		}
    		break;
    	case 6: //Matrix:Ax = b solving for x
    		if(!someOrBothBoxesFilled()) return;
    		try
    		{
    			this.matrix = (Matrix) global.get(global.getLeft());
    			global.setResultColVector(matrix.axbSolve((ColumnVector) global.get(global.getRight())));
    			intent = new Intent(this, ResultView.class);
				global.setOpType(6);
				startActivityForResult(intent, 0);    			
			} catch (Exception e) {
				dialog.error(e.getMessage());
				e.printStackTrace();
			}
    		break;
    	case 7: //Matrix:Multiply by C
    		if(!someOrBothBoxesFilled()) return;
    		try
    		{
    			this.matrix = (Matrix) global.get(global.getLeft());
    			this.constant = (Constant) global.get(global.getRight());
				global.setResultMatrix(this.matrix.multByConstant(this.constant.getValue()));
				intent = new Intent(this, ResultView.class);
				global.setOpType(0);
				startActivityForResult(intent, 0);
			} catch (Exception e) {
				dialog.error(e.getMessage());
				e.printStackTrace();
			}
    		break;
    	case 8: //Matrix:Null Space
    		if(BothBoxesFilled())
    		{
    			dialog.ask(this.left.getText().toString(), this.right.getText().toString());
    		}
    		else if(!(global.getLeft() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());
        			global.setResultColVector(matrix.nullSpace());
        			intent = new Intent(this, ResultView.class);
    				global.setOpType(9);
    				startActivityForResult(intent, 0);
    			} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else if(!(global.getRight() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());
        			global.setResultColVector(matrix.nullSpace());
        			intent = new Intent(this, ResultView.class);
    				global.setOpType(9);
    				startActivityForResult(intent, 0);
				} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			dialog.error("The two boxes are empty");
    		}
    		break;
    	case 9://Heat Map
    		if(BothBoxesFilled())
    		{
    			dialog.ask(this.left.getText().toString(), this.right.getText().toString());
    		}
    		else if(!(global.getLeft() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());
        			global.setResultMatrix(matrix);
        			intent = new Intent(this, HeatMap.class);
     			    startActivityForResult(intent, 0);
    			} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else if(!(global.getRight() < 0))
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());
        			global.setResultMatrix(matrix);
        			intent = new Intent(this, HeatMap.class);
     			    startActivityForResult(intent, 0);
				} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			dialog.error("The two boxes are empty");
    		}
    		break;
    	case 10: //Vector:Dot Product
    		if(!someOrBothBoxesFilled()) return;
    		try
    		{
    			this.vector = (Vector) global.get(global.getLeft());
    			Vector vector2 = (Vector) global.get(global.getRight());
    			dialog.show("result", this.vector.dotProduct(this.vector.getData(), vector2.getData()) +"");
			} catch (Exception e) {
				dialog.error(e.getMessage());
				e.printStackTrace();
			}
    		break;
    	case 11: //Vector:Cross Product
    		if(!someOrBothBoxesFilled()) return;
    		try
    		{
    			this.vector = (Vector) global.get(global.getLeft());
    			Vector vector2 = (Vector) global.get(global.getRight());
    			global.setResultVector(new Vector(vector.getName()+"x"+vector2.getName(), vector.crossProduct(vector.getData(), vector2.getData())));
    			dialog.show("result", global.getResultVector().toString());
			} catch (Exception e) {
				dialog.error(e.getMessage());
				e.printStackTrace();
			}
    		break;
    	case 12: //Vector:Addition
    		if(!someOrBothBoxesFilled()) return;
    		try
    		{
    			this.vector = (Vector) global.get(global.getLeft());
    			Vector vector2 = (Vector) global.get(global.getRight());
    			global.setResultVector(new Vector(vector.getName()+"x"+vector2.getName(), vector.addVector(vector.getData(), vector2.getData())));
    			dialog.show("result", global.getResultVector().toString());
			} catch (Exception e) {
				dialog.error(e.getMessage());
				e.printStackTrace();
			}
    		break;
    	case 13: //Vector:Projections
    		if(!someOrBothBoxesFilled()) return;
    		try
    		{
    			// ERRPR METHOD DOESN'T EXIST IN VECTOR CLASS -- ADD IT PLEASE.
			} catch (Exception e) {
				dialog.error(e.getMessage());
				e.printStackTrace();
			}
    		break;
    	case 14: //Vector:Multiply by C
    		if(!someOrBothBoxesFilled()) return;
    		try
    		{
    			this.vector = (Vector) global.get(global.getLeft());
    			this.constant = (Constant) global.get(global.getRight());
    	//		global.setResultVector(this.vector.multiplyByC(constant.getValue()));
				dialog.show("result", global.getResultVector().toString());
			} catch (Exception e) {
				dialog.error(e.getMessage());
				e.printStackTrace();
			}
    		break;
    	case 15: //Vector:Magnitude
    		if(BothBoxesFilled())
    		{
    			dialog.ask(this.left.getText().toString(), this.right.getText().toString());
    		}
    		else if(!(global.getLeft() < 0))
    		{
    			try 
    			{
    				this.vector = (Vector) global.get(global.getLeft());
	    			dialog.show("Result", this.vector.magnitude(this.vector.getData())+"");
				} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else if(!(global.getRight() < 0))
    		{
    			try 
    			{
    				this.vector = (Vector) global.get(global.getRight());
	    			dialog.show("Result", this.vector.magnitude(this.vector.getData())+"");
	    			} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			dialog.error("The two boxes are empty");
    		}
    		break;
    	}// end switch statement
    }
    
    /**
     * This method is triggered after the user chooses which box to perform the 
     * calculations on. 
     * @param indexOfBox "1" for left and "2" for right
     */
    public void calculateForOne(int indexOfBox)
    {
    	switch(operation)
    	{
    	case 2: //Matrix:Transpose
    		
    		if(indexOfBox == 1)
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());    				
					global.setResultMatrix(this.matrix.transpose());
					intent = new Intent(this, ResultView.class);
					global.setOpType(0);
					startActivityForResult(intent, 0);
				} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());    				
					global.setResultMatrix(this.matrix.transpose());
					intent = new Intent(this, ResultView.class);
					global.setOpType(0);
					startActivityForResult(intent, 0);
				} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		break;
    	case 3: //Matrix:Inverse
    		if(indexOfBox == 1)
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());    				
					global.setResultMatrix(this.matrix.inverse());
					intent = new Intent(this, ResultView.class);
					global.setOpType(0);
					startActivityForResult(intent, 0);
				} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());    				
					global.setResultMatrix(this.matrix.inverse());
					intent = new Intent(this, ResultView.class);
					global.setOpType(0);
					startActivityForResult(intent, 0);
				} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		break;
    	case 4: //Matrix:Determinant
    		if(indexOfBox == 1)
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());
        			dialog.show("Result", this.matrix.determinant()+"");
    			} catch (Exception e){
    				dialog.error(e.getMessage());
    				e.printStackTrace();
    			}
    		}
    		else
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());
        			dialog.show("Result", this.matrix.determinant()+"");
        		} catch (Exception e) {
    				dialog.error(e.getMessage());
    				e.printStackTrace();
    			}
    		}
    		break;
    	case 5: //Matrix:P-L-U Factorization
    		if(indexOfBox == 1)
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());
    				global.setResultMatrix(matrix.pluFactorization());
    				intent = new Intent(this, ResultView.class);
    				global.setOpType(5);
    				startActivityForResult(intent, 0);
				} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());
    				global.setResultMatrix(matrix.pluFactorization());
    				intent = new Intent(this, ResultView.class);
    				global.setOpType(5);
    				startActivityForResult(intent, 0);
				} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		break;
    	case 8: //Matrix:Null Space
    		if(indexOfBox == 1)
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());
        			global.setResultColVector(matrix.nullSpace());
        			intent = new Intent(this, ResultView.class);
    				global.setOpType(9);
    				startActivityForResult(intent, 0);
    			} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());
        			global.setResultColVector(matrix.nullSpace());
        			intent = new Intent(this, ResultView.class);
    				global.setOpType(9);
    				startActivityForResult(intent, 0);
    			} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		break;
    	case 9://Heat Map
    		if(indexOfBox == 1)
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getLeft());
        			global.setResultMatrix(matrix);
        			intent = new Intent(this, HeatMap.class);
     			    startActivityForResult(intent, 0);
    			} catch (Exception e){
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		else
    		{
    			try 
    			{
    				this.matrix = (Matrix) global.get(global.getRight());
        			global.setResultMatrix(matrix);
        			intent = new Intent(this, HeatMap.class);
     			    startActivityForResult(intent, 0);
				} catch (Exception e) {
					dialog.error(e.getMessage());
					e.printStackTrace();
				}
    		}
    		break;
    	case 15: //Vector:Magnitude
    		if(indexOfBox == 1)
    		{
        		try 
    			{
    				this.vector = (Vector) global.get(global.getLeft());
        			dialog.show("Result", this.vector.magnitude(this.vector.getData())+"");
    			} catch (Exception e){
    				dialog.error(e.getMessage());
    				e.printStackTrace();
    			}
    		}
    		else
    		{
    			try 
    			{
    				this.vector = (Vector) global.get(global.getRight());
        			dialog.show("Result", this.vector.magnitude(this.vector.getData())+"");
        			} catch (Exception e) {
    				dialog.error(e.getMessage());
    				e.printStackTrace();
    			}
    		}
    		break;
    	} // END switch statement
    } // end calculateForOne method
    
    /**
     * Method to clear the box on the left.
     */
    public void removeLeftBox()
    {
    	global.setLeft(-1);
		left.setText("");
    }
    /**
     * Method to clear the box on the right.
     */
    public void removeRightBox()
    {
		global.setRight(-1);
		right.setText("");
    }
   
    /**
     * Method to view the object inside the left box.
     */
    public void viewLeftBox()
    {
    	if(global.getLeft() < 0)
    	{
    		dialog.error("The box is empty");
    		return;
    	}
    	MathObject object = global.get(global.getLeft());
    	if(object.getTag().equals("Matrix"))
    	{
    		global.setResultMatrix((Matrix) global.get(global.getLeft()));
    		global.setOpType(0);
    		intent = new Intent(this, ResultView.class);
    		startActivityForResult(intent, 0);
    		return;
    	}
    	if(object.getTag().equals("ColVector"))
    	{
    		global.setResultColVector((ColumnVector) global.get(global.getLeft()));
    		global.setOpType(8);
    		intent = new Intent(this, ResultView.class);
    		startActivityForResult(intent, 0);
    		return;
    	}
    	else
    	{
    		dialog.view(object.getInfo());
    	}
    }
    /**
     * Method to view the object inside the right box.
     */
    public void viewRightBox()
    {
    	if(global.getRight() < 0)
    	{
    		dialog.error("The box is empty");
    		return;
    	}
    	MathObject object = global.get(global.getRight());
    	if(object.getTag().equals("Matrix"))
    	{
    		global.setResultMatrix((Matrix) global.get(global.getRight()));
    		global.setOpType(0);
    		intent = new Intent(this, ResultView.class);
    		startActivityForResult(intent, 0);
    		return;
    	}
    	if(object.getTag().equals("ColVector"))
    	{
    		global.setResultColVector((ColumnVector) global.get(global.getRight()));
    		global.setOpType(8);
    		intent = new Intent(this, ResultView.class);
    		startActivityForResult(intent, 0);
    		return;
    	}
    	else
    	{
    		dialog.view(object.getInfo());
    	}
    }
    
    /**
     * Method to clear the two boxes and the edit text.
     */
    public void reset()
    {
    	removeLeftBox();
    	removeRightBox();
		editText.setText("");
    }
    
    /**
     * Method to switch the objects in the two boxes.
     */
    public void switchBoxes()
    {
		//swap indexes in global
		int temp = 0;
		temp = global.getLeft();
		global.setLeft(global.getRight());
		global.setRight(temp);
		// swap names
		String name = "";
		name = left.getText().toString();
		left.setText(right.getText().toString());
		right.setText(name);
    }

    /**
     * method to check if the two boxes are filled
     * @return false if one box or both are empty, and true otherwise.
     */
    public boolean someOrBothBoxesFilled()
    {
    	// check if one or all boxes are empty
    	if(global.getLeft() < 0)
    	{
    		dialog.error("The left box is empty");
    		return false;
    	}
    	if(global.getRight() < 0)
    	{
    		dialog.error("The right box is empty");
    		return false;
    	}    	
    	return true;
    }
    /**
     * Method to check if BOTH boxes are empty.
     * @return true if both are empty, and false otherwise.
     */
    public boolean BothBoxesFilled()
    {
		if(!(global.getLeft() < 0) && !(global.getRight() < 0))
		{
			return true;
		}
		return false;
    }
    /*
     * setters and getters
     */
	public int getOperation(){return operation;}
	public void setOperation(int operation){this.operation = operation;}
    
	
	/**
	 * inner class for dialog
	 * @author Sultan
	 *
	 */
	class Alert extends Dialog
	{
		/**
		 * instance variables
		 */
		private	Button btn1, btn2, ok;
		private TextView title, message;
		MainActivity mat;
		// constructor
		public Alert(Context context)
		{
			super(context);
			this.requestWindowFeature(Window.FEATURE_NO_TITLE);
			setContentView(R.layout.dialog);
			this.init();
			this.setListeners();
		}
		// methods
		public void init()
		{
			this.btn1 = (Button) findViewById(R.id.dialog_box1);
			this.btn2 = (Button) findViewById(R.id.dialog_box2);
			this.ok = (Button)   findViewById(R.id.dialog_ok);
			this.title = (TextView) findViewById(R.id.dialog_title);
			this.message = (TextView) findViewById(R.id.dialog_text);
		}
		public void setListeners()
		{
			this.btn1.setOnClickListener(new Button.OnClickListener()
			{
				public void onClick(View v)
				{
					dismiss();
					MainActivity.this.calculateForOne(1);
				}
			});
			this.btn2.setOnClickListener(new Button.OnClickListener()
			{
				public void onClick(View v)
				{
					dismiss();
					MainActivity.this.calculateForOne(2);
				}
			});
			
			this.ok.setOnClickListener(new Button.OnClickListener()
			{
				public void onClick(View v)
				{
					dismiss();
				}	
			});
		}
		
		/**
		 * sets the title of the dialog.
		 * @param title
		 */
		public void setTitle(String title)
		{
			this.title.setText(title);
		}
		/**
		 * shows the dialog.
		 * @param title
		 * @param message
		 */
		public void show(String title, String message)
		{
			this.btn1.setVisibility(Button.GONE);
			this.btn2.setVisibility(Button.GONE);
			this.ok.setVisibility(Button.VISIBLE);
			setTitle(title);
			this.setMessage(message);
			show();
		}
		/**
		 * shows a dialog titled 'ERROR'.
		 * @param message
		 */
		public void error(String message)
		{
			if(message.startsWith("com.matrix"))
			{
				this.show("ERROR", "Operation is not applicable");
			}
			else
			{
				this.show("ERROR", message);
			}
		}
		
		/**
		 * shows a dialog that has two buttons and asks the user to choose one.
		 * @param first
		 * @param second
		 */
		public void ask(String first, String second)
		{
			this.btn1.setVisibility(Button.VISIBLE);
			this.btn2.setVisibility(Button.VISIBLE);
			this.ok.setVisibility(Button.GONE);
			this.btn1.setText(first);
			this.btn2.setText(second);
			this.setTitle("Select");
			this.setMessage("Please choose one");
			show();
		}
		/**
		 * shows a dialog titled 'View'
		 * @param message
		 */
		public void view(String message)
		{
			this.show("View", message);
		}
		public void setMessage(String message){this.message.setText(message);}
	}

}